package com.hexingmo.dawn.lang;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author He Xing Mo
 * @since 1.0
 */
public class ClassUtils {

    /**
     * 基本数据类名称和类型映射 Map
     */
    private static final Map<String, Class<?>> PRIMITIVE_NAME_TYPE_MAP;

    /** 数组类型名称后缀: "[]" */
    private static final String ARRAY_SUFFIX = "[]";

    /**
     * "[" 标识数组类型
     */
    private static final String INTERNAL_ARRAY_PREFIX = "[";

    /**
     * "[" 标识数组类型 , "L" 标识引用类型(即非基本数据类型),后面跟着类的全限定名，最后以 ";" 结束。
     */
    private static final String REFERENCE_ARRAY_PREFIX = "[L";

    public static final char PACKAGE_SEPARATOR_CHAR = '.';

    public static final char INNER_CLASS_SEPARATOR_CHAR = '$';

    public static final String SEMICOLON = ";";

    public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);

    static {
        Map<String , Class<?>> primitiveNameTypeMap = new HashMap<>(32);
        primitiveNameTypeMap.putAll(Primitives.PRIMITIVE_NAME_CLASS_MAP);
        primitiveNameTypeMap.put(boolean[].class.getName() , boolean[].class);
        primitiveNameTypeMap.put(byte[].class.getName() , byte[].class);
        primitiveNameTypeMap.put(char[].class.getName() , char[].class);
        primitiveNameTypeMap.put(short[].class.getName() , short[].class);
        primitiveNameTypeMap.put(int[].class.getName() , int[].class);
        primitiveNameTypeMap.put(long[].class.getName() , long[].class);
        primitiveNameTypeMap.put(float[].class.getName() , float[].class);
        primitiveNameTypeMap.put(double[].class.getName() , double[].class);

        PRIMITIVE_NAME_TYPE_MAP = Collections.unmodifiableMap(primitiveNameTypeMap);
    }


    private ClassUtils() {
        throw new IllegalStateException("Static utility classes do not support instantiation");
    }

    /**
     * 将对象强制转换为指定的类型，如果转换失败则抛出 ClassCastException。
     *
     * @param obj 要转换的对象
     * @param type 目标类型
     * @param <T> 目标类型的泛型参数
     * @return 转换后的对象
     * @throws ClassCastException 如果对象无法转换为目标类型，则抛出此异常
     */
    public static <T> T cast(Object obj , Class<T> type) {
        Assert.notNull(obj , "obj arg must not be null");
        Assert.notNull(type , "type arg must not be null");
        if (canCast(obj , type)) {
            return type.cast(obj);
        }
        throw new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + type.getName());
    }

    /**
     * 检查对象是否可以转换为指定的类型。
     *
     * @param obj 要检查的对象
     * @param type 目标类型
     * @return 如果对象可以转换为目标类型则返回 true，否则返回 false
     */
    public static boolean canCast(Object obj , Class<?> type) {
        if (obj == null || type == null) {
            return false;
        }
        return obj.getClass() == type || type.isInstance(obj.getClass());
    }

    /**
     * 获取对象的类类型。
     *
     * @param obj 要获取类类型的对象
     * @return 对象的类类型，如果对象为 null，则返回 null
     */
    public static <T> Class<T> getClass(T obj) {
        return obj == null ? null : (Class<T>) obj.getClass();
    }

    /**
     * 根据类名加载类，默认情况下会进行类的初始化。
     *
     * @param className 要加载的类的全限定名（包名 + 类名）
     * @return 加载的类对象
     * @throws ClassNotFoundException 如果指定的类名在类路径中找不到，则会抛出此异常
     */
    public static Class<?> getClass(final String className) throws ClassNotFoundException {
        return getClass(className, true);
    }

    /**
     * 根据类名和初始化标志加载类。
     *
     * @param className  要加载的类的全限定名（包名 + 类名）
     * @param initialize 是否在加载类时对其进行初始化
     *                   - 如果为 true，则会触发类的静态初始化块和静态变量的初始化。
     *                   - 如果为 false，则不会触发类的初始化，直到类被实际使用时才会进行初始化。
     * @return 加载的类对象
     * @throws ClassNotFoundException 如果指定的类名在类路径中找不到，则会抛出此异常
     */
    public static Class<?> getClass(final String className , final boolean initialize) throws ClassNotFoundException {
        final ClassLoader ccl = ClassLoaders.getCurrentThreadClassLoader();
        final ClassLoader loader = ccl == null ? ClassLoaders.getDefaultClassLoader() : ccl;
        return getClass(loader , className , initialize);
    }

    /**
     * 根据类加载器、类名和初始化标志加载类。支持基本数据类型类的加载。
     *
     * @param classLoader 用于加载类的类加载器
     * @param className   要加载的类的全限定名（包名 + 类名）
     * @param initialize  是否在加载类时对其进行初始化
     *                    - 如果为 true，则会触发类的静态初始化块和静态变量的初始化。
     *                    - 如果为 false，则不会触发类的初始化，直到类被实际使用时才会进行初始化。
     * @return 加载的类对象
     * @throws ClassNotFoundException 如果指定的类名在类路径中找不到，则会抛出此异常
     */
    public static Class<?> getClass(ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
        // 基本数据类型加载
        Class<?> clazz = PRIMITIVE_NAME_TYPE_MAP.get(className);
        if (clazz != null) {
            return clazz;
        }

        if (classLoader == null) {
            classLoader = ClassLoaders.getDefaultClassLoader();
        }

        // 数组类型例如: "java.lang.String[]"
        if (className.endsWith(ARRAY_SUFFIX)) {
            final String elementClassName = className.substring(0, className.length() - ARRAY_SUFFIX.length());
            final Class<?> elementClass = getClass(classLoader ,elementClassName, initialize);
            return Array.newInstance(elementClass, 0).getClass();
        }

        // 引用数组类型，例如: "[Ljava.lang.String;"
        if (className.startsWith(REFERENCE_ARRAY_PREFIX) && className.endsWith(SEMICOLON)) {
            final String elementClassName = className.substring(REFERENCE_ARRAY_PREFIX.length(), className.length() - 1);
            final Class<?> elementClass = getClass(classLoader ,elementClassName, initialize);
            return Array.newInstance(elementClass, 0).getClass();
        }

        // 数组类型,例如: "[[I" or "[[Ljava.lang.String;" 表示二维数组
        if (className.startsWith(INTERNAL_ARRAY_PREFIX)) {
            final String elementClassName = className.substring(INTERNAL_ARRAY_PREFIX.length());
            final Class<?> elementClass = getClass(classLoader ,elementClassName, initialize);
            return Array.newInstance(elementClass, 0).getClass();
        }

        // 加载普通类型
        try {
            return Class.forName(className, initialize, classLoader);
        } catch (ClassNotFoundException ex) {
            clazz = getInnerClass(classLoader, className, initialize , false);
            if (clazz != null) {
                return clazz;
            }
            throw ex;
        }
    }

    /**
     * 获取内部类的 Class 对象。
     * <p>
     * 该方法通过类名解析出内部类的全限定名，并尝试加载对应的 Class 对象。
     * 如果类名中包含包名分隔符（'.'），则会将最后一个 '.' 替换为内部类分隔符（'$'），
     * 并递归调用 {@link #getClass(ClassLoader, String, boolean)} 方法加载类。
     * 如果加载失败且未设置抛出异常标志，则返回 null。
     *
     * @param classLoader 用于加载类的类加载器
     * @param className   要加载的类的全限定名（包名 + 类名）
     * @param initialize  是否在加载类时对其进行初始化
     *                    - 如果为 true，则会触发类的静态初始化块和静态变量的初始化。
     *                    - 如果为 false，则不会触发类的初始化，直到类被实际使用时才会进行初始化。
     * @param throwException 如果加载失败是否抛出异常
     *                       - 如果为 true，则在加载失败时抛出 {@link ClassNotFoundException}。
     *                       - 如果为 false，则返回 null。
     * @return 加载的内部类的 Class 对象，如果加载失败且未设置抛出异常标志，则返回 null
     * @throws ClassNotFoundException 如果指定的类名在类路径中找不到且设置了抛出异常标志，则会抛出此异常
     */
    public static Class<?> getInnerClass(ClassLoader classLoader, final String className, final boolean initialize , final boolean throwException) throws ClassNotFoundException {
        final int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
        if (lastDotIndex != -1) {
            try {
                String innerClassName = className.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1);
                return getClass(classLoader, innerClassName , initialize);
            } catch (final ClassNotFoundException ex) {
                if (throwException) {
                    throw ex;
                }
            }
        }
        return null;
    }


    /**
     * 检查给定的类是否为基本类型。
     *
     * @param type 要检查的类
     * @return 如果类是基本类型则返回 true，否则返回 false
     */
    public static boolean isPrimitive(Class<?> type) {
        return Primitives.isPrimitive(type);
    }

    /**
     * 检查给定的类是否为基本类型的包装类。
     *
     * @param type 要检查的类
     * @return 如果类是基本类型的包装类则返回 true，否则返回 false
     */
    public static boolean isPrimitiveWrapper(Class<?> type) {
        return Primitives.isPrimitiveWrapper(type);
    }

    /**
     * 检查给定的类是否为基本类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是基本类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isPrimitiveOrWrapper(Class<?> type) {
        return Primitives.isPrimitiveOrWrapper(type);
    }

    /**
     * 检查给定的类是否为基本类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是基本类型的数组则返回 true，否则返回 false
     */
    public static boolean isPrimitiveArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isPrimitive(type.getComponentType());
    }

    /**
     * 检查给定的类是否为基本类型包装类的数组。
     *
     * @param type 要检查的类
     * @return 如果类是基本类型包装类的数组则返回 true，否则返回 false
     */
    public static boolean isPrimitiveWrapperArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isPrimitiveWrapper(type.getComponentType());
    }

    /**
     * 检查给定的类是否为基本类型或其包装类的数组。
     *
     * @param type 要检查的类
     * @return 如果类是基本类型或其包装类的数组则返回 true，否则返回 false
     */
    public static boolean isPrimitiveOrWrapperArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return isPrimitiveArray(type) || isPrimitiveWrapperArray(type);
    }

    /**
     * 检查给定的类是否为 boolean 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 boolean 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isBoolean(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Boolean.TYPE == type || type == Boolean.class;
    }

    /**
     * 检查给定的类是否为 char 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 char 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isChar(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Character.TYPE == type || type == Character.class;
    }

    /**
     * 检查给定的类是否为 byte 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 byte 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isByte(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Byte.TYPE == type || type == Byte.class;
    }

    /**
     * 检查给定的类是否为 short 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 short 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isShort(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Short.TYPE == type || type == Short.class;
    }

    /**
     * 检查给定的类是否为 int 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 int 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isInt(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Integer.TYPE == type || type == Integer.class;
    }

    /**
     * 检查给定的类是否为 long 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 long 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isLong(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Long.TYPE == type || type == Long.class;
    }

    /**
     * 检查给定的类是否为 float 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 float 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isFloat(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Float.TYPE == type || type == Float.class;
    }

    /**
     * 检查给定的类是否为 double 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 double 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isDouble(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Double.TYPE == type || type == Double.class;
    }

    /**
     * 检查给定的类是否为 void 类型或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是 void 类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isVoid(Class<?> type) {
        if (type == null) {
            return false;
        }
        return Void.TYPE == type || type == Void.class;
    }

    /**
     * 检查给定的类是否为数值类型（int, long, float, double）或其包装类。
     *
     * @param type 要检查的类
     * @return 如果类是数值类型或其包装类则返回 true，否则返回 false
     */
    public static boolean isNumeric(Class<?> type) {
        if (type == null) {
            return false;
        }
        return isInt(type) || isLong(type) || isFloat(type) || isDouble(type);
    }

    /**
     * 检查给定的类是否为引用类型（非基本类型）。
     * @param type 要检查的类
     * @return 如果类是引用类型（非基本类型）则返回 true，否则返回 false
     */
    public static boolean isReferenceType(Class<?> type) {
        return !Primitives.isPrimitive(type);
    }

    /**
     * 检查给定的类是否为引用类型（非基本类型，非包装类）。
     * @param type 要检查的类
     * @return 如果类是引用类型（非基本类型，非包装类）则返回 true，否则返回 false
     */
    public static boolean isReferenceTypeExcludeWrapper(Class<?> type) {
        return !Primitives.isPrimitiveOrWrapper(type);
    }

    /**
     * 判断Class是否是强引用类型
     * 强引用是Java的默认引用类型，不是Reference的子类,只要强引用存在，垃圾回收器就永远不会回收被引用的对象.
     *
     * @param clazz 要检查的Class对象
     * @return true表示是强引用类型，false表示不是
     */
    public static boolean isStrongReference(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }

        // 强引用不是Reference的子类，且不是基本类型
        return !Reference.class.isAssignableFrom(clazz) && !Primitives.isPrimitive(clazz);
    }

    /**
     * 判断Class是否是软引用类型.
     * 软引用当内存不足时，垃圾回收器会回收它所引用的对象。
     * @param clazz 要检查的Class对象
     * @return true表示是软引用类型，false表示不是
     */
    public static boolean isSoftReference(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }

        return SoftReference.class.isAssignableFrom(clazz);
    }

    /**
     * 判断Class是否是弱引用类型.
     * 弱引用比软引用更弱，只要垃圾回收器运行，弱引用对象就会被回收。
     * @param clazz 要检查的Class对象
     * @return true表示是弱引用类型，false表示不是
     */
    public static boolean isWeakReference(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }

        return WeakReference.class.isAssignableFrom(clazz);
    }

    /**
     * 判断Class是否是虚引用类型。
     * 虚引用是最弱的引用类型，主要用于跟踪对象被垃圾回收的状态。
     * @param clazz 要检查的Class对象
     * @return true表示是虚引用类型，false表示不是
     */
    public static boolean isPhantomReference(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }

        return PhantomReference.class.isAssignableFrom(clazz);
    }


    /**
     * 检查给定的类是否为 boolean 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 boolean 类型的数组则返回 true，否则返回 false
     */
    public static boolean isBooleanArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isBoolean(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 char 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 char 类型的数组则返回 true，否则返回 false
     */
    public static boolean isCharArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isChar(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 byte 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 byte 类型的数组则返回 true，否则返回 false
     */
    public static boolean isByteArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isByte(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 short 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 short 类型的数组则返回 true，否则返回 false
     */
    public static boolean isShortArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isShort(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 int 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 int 类型的数组则返回 true，否则返回 false
     */
    public static boolean isIntArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isInt(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 long 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 long 类型的数组则返回 true，否则返回 false
     */
    public static boolean isLongArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isLong(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 float 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 float 类型的数组则返回 true，否则返回 false
     */
    public static boolean isFloatArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isFloat(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 double 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 double 类型的数组则返回 true，否则返回 false
     */
    public static boolean isDoubleArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isDouble(type.getComponentType());
    }

    /**
     * 检查给定的类是否为 void 类型的数组。
     *
     * @param type 要检查的类
     * @return 如果类是 void 类型的数组则返回 true，否则返回 false
     */
    public static boolean isVoidArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return type.isArray() && isVoid(type.getComponentType());
    }

    /**
     * 检查给定的类是否为数值类型（int, long, float, double）的数组。
     *
     * @param type 要检查的类
     * @return 如果类是数值类型或其包装类的数组则返回 true，否则返回 false
     */
    public static boolean isNumericArray(Class<?> type) {
        if (type == null) {
            return false;
        }
        return isIntArray(type) || isLongArray(type) || isFloatArray(type) || isDoubleArray(type);
    }
}
